"""
玩家以及和游戏相关内容
"""
from multiprocessing.sharedctypes import Value
from faker import Faker
from meta.utils import LogMixin
from game.token import Tokens
from game.history import PlayerHistory
from game.strategy import DoubleEveryTimeStrategy
from game.object import Coin

class NoMoneyError(ValueError):
    """没有钱错误"""
    def __init__(self, *args: object) -> None:
        super().__init__(*args)



class Player(LogMixin):
    """玩家类

    玩家包括庄家和赌徒。
    属性：
        name: 玩家名称
        wallet: 玩家钱包
        history: 玩家历史记录

    方法：
        determine: 玩家决定结果
        record: 记录玩家历史分数
        bet: 下注

    """

    def __init__(self, name: str=None, tokens:Tokens=None) -> None:
        super().__init__()
        if name is None:
            name = Faker("zh_CN").name()
        if tokens is None:
            self.wallet = Tokens()
        else:
            self.wallet = tokens
        self.history = PlayerHistory()
        self.logger.info('玩家%s初始化完毕', {self.name})

    def determin(self):
        """玩家决定结果"""
        raise NotImplementedError

    def record(self, win: bool, wage: int):
        """将情况记录到历史记录中

        win: 是否胜利
        wage: 下注大小
        _score: 当前分数

        """
        self.history["win"].append(win)
        self.history["wage"].append(wage)
        self.history["score"].append(self.score)
        self.logger.info(f'玩家{self.name}记录胜利{win}下注{wage}分数{self.score}')

    def bet(self, num: int) -> Tokens:
        """玩家使用wallet中的token下注
        
        钱不够时抛出NoMoneyError异常

        返回：
            下注的tokens类

        """
        self.logger.info(f'玩家{self.name}下注{num}币')
        try: 
             betting = self.wallet - num
        except ValueError as e:
            self.logger.error(e)
            raise NoMoneyError
        finally:
            return betting

# ---------------------------------------------------------------------------------------------------------------------------------------------------------------

class Host(Player):
    """庄家类

    包含庄家能够做的事情、庄家的策略。

    """

    def __init__(self, name=None):
        super(Host, self).__init__(name=name)
        self.logger.info(f'庄家{self.name}初始化完毕')

    def determin(self, num):
        """庄家决策

        接受赌徒提供的赌注大小（实际上是荷官提供），并以相同的大小下注。庄家无需进行下注。
        庄家钱不够时自动生成足够的钱。

        """
        return self.bet(num=num)

    def __str__(self):
        return self.name


class Gambler(Player):
    """赌徒类
    """

    def __init__(self, name, scores):
        super(Gambler, self).__init__(name, scores)
        self.logger.info(f'赌徒{self.name}初始化完毕')

    def determin(self, stand_coin_class=Coin(num=2)):
        """赌徒决策"""

        # 根据策略下注
        idea = DoubleEveryTimeStrategy(self)
        betting = self.bet(num=idea.calculate())

        # 扔硬币，预测结果
        coin_num = self.__flip(stand_coin_class)

        return betting, coin_num  # 返回下注的分数和硬币正反

    def __flip(self, StandCoin=Coin):
        """赌徒扔硬币

        赌徒扔硬币，并返回硬币的正反。

        """
        coin = StandCoin()
        coin_num = coin.flip()
        self.logger.info(f'赌徒{self.name}扔出{coin_num}')
        return coin_num
